/**
 * 
 */
package org.vsg.common.web.spring;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.BeanUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping;

/**
 * @author Bill vison
 *
 */
public class HandlerInterceptorAnnotationAwareHandlerMapping extends
		DefaultAnnotationHandlerMapping {

	/**
	 * Override the getHandlerExecutionChain() method defined in DefaultAnnotationHandlerMapping
	 */
	@Override
    protected HandlerExecutionChain getHandlerExecutionChain(Object handler,HttpServletRequest request){ 

		/**
         * Call ‘super()’ so that you don’t change the base class behavior . This way you can aggregate the interceptors configured
         * in the Spring context file against the property ‘interceptors’ as well (it at all configured) .
         */
		HandlerExecutionChain chain = super.getHandlerExecutionChain(handler,request);  
        
		HandlerInterceptor[] interceptors = detectInterceptors(chain.getHandler().getClass());
        
		chain.addInterceptors(interceptors);
        
		return chain;
    }

	protected HandlerInterceptor[] detectInterceptors(Class handlerClass) {
		
		/**
		 * Look for @Interceptors annotation for a given Controller class.
		 */
        Interceptors interceptorAnnot = AnnotationUtils.findAnnotation(handlerClass, Interceptors.class);    

        List<HandlerInterceptor> interceptors = new ArrayList();
        if (interceptorAnnot != null) {
          Class[] interceptorClasses = interceptorAnnot.value();
          if (interceptorClasses != null) {
            for (Class interceptorClass : interceptorClasses) {     
              if (!HandlerInterceptor.class.isAssignableFrom(interceptorClass)) {
                raiseIllegalInterceptorValue(handlerClass,interceptorClass);      
              }
              interceptors.add((HandlerInterceptor) BeanUtils.instantiateClass(interceptorClass));  
            }
          }
        }
        return interceptors.toArray(new HandlerInterceptor[0]);
    }
	
	protected void raiseIllegalInterceptorValue(Class handlerClass,Class interceptorClass) {
        throw new IllegalArgumentException(interceptorClass + " specified on "
            + handlerClass + " does not implement " + HandlerInterceptor.class.getName());

    }
	
}
